La manipulación del DOM y el manejo de eventos son pilares clave en el desarrollo de interfaces dinámicas con JavaScript. El DOM (Document Object Model) es la estructura jerárquica de un documento HTML que JavaScript puede modificar en tiempo real. Los eventos permiten a los desarrolladores capturar acciones del usuario, como clics, teclas presionadas, desplazamientos, etc., para modificar la página de forma interactiva.
La manipulación del DOM permite modificar elementos, contenido y estilos de una página web en respuesta a eventos o lógicas definidas. Esto permite generar experiencias dinámicas e interactivas para los usuarios.
Para trabajar con el DOM, lo primero es seleccionar los elementos con los que se va a interactuar. JavaScript ofrece varios métodos para acceder a los elementos del DOM:
document.getElementById(id)
: Selecciona un elemento por su ID.document.querySelector(selector)
: Selecciona el primer elemento que coincida con un selector CSS.document.querySelectorAll(selector)
: Selecciona todos los elementos que coincidan con un selector CSS.// Ejemplo: seleccionar un elemento por su ID
let titulo = document.getElementById('titulo');
Una vez seleccionado un elemento, podemos modificar su contenido, estilo o atributos:
innerHTML
, textContent
):// Cambiar el contenido del título
titulo.textContent = 'Nuevo Título';
// Cambiar el color del texto
titulo.style.color = 'blue';
// Cambiar el valor de un atributo
titulo.setAttribute('class', 'nuevo-estilo');
JavaScript permite agregar nuevos elementos al DOM o eliminar los existentes:
let nuevoParrafo = document.createElement('p');
nuevoParrafo.textContent = 'Este es un nuevo párrafo';
document.body.appendChild(nuevoParrafo);
let parrafo = document.querySelector('p');
parrafo.remove();
Los eventos en JavaScript permiten a las aplicaciones web responder a interacciones del usuario. Un evento puede ser cualquier cosa, desde un clic, hasta el movimiento del ratón, la escritura en un campo de texto o la carga de la página.
click
, dblclick
, mouseenter
, mouseleave
, mouseover
, etc.keydown
, keyup
, keypress
.submit
, change
, input
, etc.load
, resize
, scroll
, unload
.Para ejecutar código cuando ocurre un evento, se deben asignar "listeners" (escuchadores de eventos) a los elementos. La forma más común es usar addEventListener()
.
// Escuchar el evento 'click' en un botón
let boton = document.getElementById('miBoton');
boton.addEventListener('click', function() {
alert('Botón clickeado!');
});
Algunos eventos tienen comportamientos predeterminados que no siempre son deseados, como la recarga de la página al enviar un formulario. Con event.preventDefault()
, es posible evitarlo:
let formulario = document.querySelector('form');
formulario.addEventListener('submit', function(event) {
event.preventDefault(); // Evita que la página se recargue
console.log('Formulario enviado');
});
Los eventos pueden propagarse en el DOM a través de dos fases: la fase de captura y la fase de burbuja. Esto significa que un evento, como un clic, puede propagarse desde el elemento más específico (el que recibe el clic) hasta el más general (por ejemplo, document
).
Se puede detener la propagación del evento utilizando event.stopPropagation()
.
let innerDiv = document.getElementById('inner');
let outerDiv = document.getElementById('outer');
innerDiv.addEventListener('click', function(event) {
console.log('Clic en inner div');
event.stopPropagation(); // Detiene la propagación
});
outerDiv.addEventListener('click', function() {
console.log('Clic en outer div');
});
En este ejemplo, solo se registrará el clic en el innerDiv
, y no en el outerDiv
, gracias a stopPropagation()
.
<div id="outer" style="padding: 50px; background-color: lightblue;">
Outer Div
<div id="middle" style="padding: 50px; background-color: lightgreen;">
Middle Div
<div id="inner" style="padding: 50px; background-color: lightcoral;">
Inner Div
</div>
</div>
</div>
<script>
let innerDiv = document.getElementById('inner');
let middleDiv = document.getElementById('middle');
let outerDiv = document.getElementById('outer');
// Fase de burbuja (por defecto)
innerDiv.addEventListener('click', function(event) {
console.log('Clic en inner div (burbuja)');
});
middleDiv.addEventListener('click', function(event) {
console.log('Clic en middle div (burbuja)');
});
outerDiv.addEventListener('click', function(event) {
console.log('Clic en outer div (burbuja)');
});
// Fase de captura
innerDiv.addEventListener('click', function(event) {
console.log('Clic en inner div (captura)');
}, true);
middleDiv.addEventListener('click', function(event) {
console.log('Clic en middle div (captura)');
}, true);
outerDiv.addEventListener('click', function(event) {
console.log('Clic en outer div (captura)');
}, true);
</script>
Explicación:
addEventListener
a true
.addEventListener
usa la fase de burbuja.Al hacer clic en el innerDiv
, verás primero los mensajes de la fase de captura (desde el nodo más exterior hasta el más interior), y luego los de la fase de burbuja (del nodo más interior al exterior).
stopPropagation
En este ejemplo, utilizaremos event.stopPropagation()
para detener la propagación del evento en ambas fases.
<div id="outer" style="padding: 50px; background-color: lightblue;">
Outer Div
<div id="middle" style="padding: 50px; background-color: lightgreen;">
Middle Div
<div id="inner" style="padding: 50px; background-color: lightcoral;">
Inner Div
</div>
</div>
</div>
<script>
let innerDiv = document.getElementById('inner');
let middleDiv = document.getElementById('middle');
let outerDiv = document.getElementById('outer');
innerDiv.addEventListener('click', function(event) {
console.log('Clic en inner div');
event.stopPropagation(); // Detiene la propagación
});
middleDiv.addEventListener('click', function() {
console.log('Clic en middle div');
});
outerDiv.addEventListener('click', function() {
console.log('Clic en outer div');
});
</script>
Explicación:
innerDiv
, solo se registrará el evento en el innerDiv
, ya que event.stopPropagation()
detiene la propagación hacia los nodos middleDiv
y outerDiv
.middleDiv
, el evento se propagaría hasta outerDiv
porque no se ha detenido la propagación.event.stopImmediatePropagation()
event.stopImmediatePropagation()
detiene la propagación del evento y también evita que otros event listeners en el mismo nodo se ejecuten.
<div id="outer" style="padding: 50px; background-color: lightblue;">
Outer Div
<div id="middle" style="padding: 50px; background-color: lightgreen;">
Middle Div
<div id="inner" style="padding: 50px; background-color: lightcoral;">
Inner Div
</div>
</div>
</div>
<script>
let innerDiv = document.getElementById('inner');
innerDiv.addEventListener('click', function() {
console.log('Clic en inner div - primer listener');
});
innerDiv.addEventListener('click', function(event) {
console.log('Clic en inner div - segundo listener');
event.stopImmediatePropagation(); // Detiene otros listeners en el mismo nodo
});
innerDiv.addEventListener('click', function() {
console.log('Clic en inner div - tercer listener');
});
</script>
Explicación:
innerDiv
, solo se ejecutarán el primer y segundo listener. El tercer listener no se ejecutará debido a stopImmediatePropagation()
.Uno de los casos más comunes es modificar el contenido de la página en respuesta a las interacciones del usuario. Por ejemplo, un menú que se despliega al hacer clic en un botón.
<button id="toggleMenu">Abrir Menú</button>
<ul id="menu" style="display: none;">
<li>Inicio</li>
<li>Sobre Nosotros</li>
<li>Contacto</li>
</ul>
<script>
let menu = document.getElementById('menu');
let toggleButton = document.getElementById('toggleMenu');
toggleButton.addEventListener('click', function() {
if (menu.style.display === 'none') {
menu.style.display = 'block';
} else {
menu.style.display = 'none';
}
});
</script>
JavaScript permite validar formularios o añadir campos de forma dinámica según las acciones del usuario, lo que mejora la experiencia del usuario y reduce errores.
Imagina un formulario en el que los usuarios pueden agregar varios correos electrónicos (o cualquier otro dato) de manera dinámica. En este caso, cada vez que el usuario hace clic en un botón "Agregar Email", se genera un nuevo campo de entrada de texto. También hay un botón para eliminar campos agregados si el usuario así lo desea.
<form id="emailForm">
<div id="emailFields">
<div class="emailField">
<label for="email1">Email 1:</label>
<input type="email" name="email[]" id="email1">
</div>
</div>
<button type="button" id="addEmail">Agregar Email</button>
<button type="submit">Enviar</button>
</form>
let emailCounter = 1; // Para contar cuántos campos de email hay
let emailForm = document.getElementById('emailForm');
let addEmailButton = document.getElementById('addEmail');
let emailFields = document.getElementById('emailFields');
// Función para agregar un nuevo campo de email
addEmailButton.addEventListener('click', function() {
emailCounter++; // Aumenta el contador de emails
// Crear un nuevo div contenedor para el email
let newEmailDiv = document.createElement('div');
newEmailDiv.classList.add('emailField');
// Agregar un campo de entrada para el nuevo email
newEmailDiv.innerHTML = `
<label for="email${emailCounter}">Email ${emailCounter}:</label>
<input type="email" name="email[]" id="email${emailCounter}">
<button type="button" class="removeEmail">Eliminar</button>
`;
// Agregar el nuevo campo al contenedor de emails
emailFields.appendChild(newEmailDiv);
// Añadir funcionalidad para eliminar este campo de email
newEmailDiv.querySelector('.removeEmail').addEventListener('click', function() {
newEmailDiv.remove(); // Elimina el campo de email del formulario
});
});
// Funcionalidad para enviar el formulario
emailForm.addEventListener('submit', function(event) {
event.preventDefault(); // Evita el envío real del formulario
let formData = new FormData(emailForm); // Recolecta todos los datos del formulario
console.log('Emails ingresados:', formData.getAll('email[]')); // Muestra todos los emails en la consola
// Aquí podrías procesar los datos o hacer un envío real usando fetch()
});
Explicación:
Objetivo: Crear un grid de imágenes interactivo, añadir botones que cambien tanto el layout del grid como el estilo de las imágenes al hacer clic en los botones.
Cambios en el layout del grid:
Cambios en el estilo de las imágenes:
Interacción de las imágenes:
Puntos a evaluar: